#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<string.h>
#define NUM 1024   //用户输入的最大个数
#define CMD_NUM 64 //命名行参数的个数
int main()
{
    while(1)
    {
        char buf[NUM] = {0}; //保存用户输入
        //0.输入提示符
        printf("[who@dirname #]");//注意：不换行，因为用户输入的在提示符后面
        fflush(stdout);//刷新缓冲区
        //1.获取用户输入 --版本1：使用fgets(保存到哪，期望读取多少字节，从哪里读)
        fgets(buf,NUM-1,stdin);//从键盘当中读取会把\n也读取进去
        buf[strlen(buf) -1] = '\0'; //hello\n\0  要把\n位置置为\0

        //版本2-使用read函数 (从哪个文件描述符进行读取,读到哪,期望读取多少字节)
        // ssize_t n = read(0,buf,NUM-1); //返回实际读取的字节个数
        // if(n > 0) //会把\n也读进去 
        //     buf[n-1] = '\0';//hello\n\0 把\n位置置为\0
        
        //2.解析命令行
        char* cmd[CMD_NUM] = {NULL};//保存分割好的命令行参数
        const char* sep = " "; //分隔符
        cmd[0] = strtok(buf,sep);
        int index = 1;
        while(cmd[index++] = strtok(NULL,sep)) ;
        //2.1.判断是否是内建命令
        if(strcmp("cd",cmd[0]) == 0)
        {
            if(cmd[1])
                chdir(cmd[1]);
        }
        //2.2 创建子进程, 执行程序替换
        pid_t id = fork();
        if(id == 0)
        {
            //由于cmd[0]就是要执行的命令，且不带路径，所以要选择带p的
            //由于我们是用数组保存命令行参数(如何执行这个程序)，所以要选择带v的
            execvp(cmd[0],cmd);
        }
        //3.等待子进程退出，输出子进程的退出信息  
        int status = 0;
        int ret = waitpid(id,&status,0);// waitpid执行成功返回等待的子进程的pid
        if(ret > 0) //打印退出信息区分当前用的是我们自己的minishell
        {
             printf("exitCode:%d,exitSignal:%d,core dump yes or no:%d\n", \
         (status >> 8)&0xff,status&0x7f,(status>>7)&1);
        }
    }
    
    return 0;
}